package com.gillion.grule.client.sync;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gillion.grule.client.core.DroolsRuleCompiler;
import com.gillion.grule.client.core.HolidaysModel;
import com.gillion.grule.client.core.Rule;
import com.gillion.grule.client.core.RuleBuilder;
import com.gillion.grule.client.utils.Holidays;

import java.util.HashMap;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;







public class ZookeeperRuleCacheProvider<ESBClient> extends RuleCacheProvider<DroolsRulePackage>
        implements TreeCacheListener
{
    private static final Logger log = LoggerFactory.getLogger(ZookeeperRuleCacheProvider.class);

    private String zookeeperConnectionStr;

    private String ruleBasePath;

    private String ruleProviderServiceCode;

    private DroolsRuleCompiler ruleCompiler;

    private CuratorFramework curatorFramework;

    private ESBClient esbClient;

    private String nameSpace;

    private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperRuleCacheProvider.class);

    private String holidaysUrl;

    public void init() throws Exception {
        if (this.zookeeperConnectionStr != null) {
            if (this.ruleBasePath != null) {
                ExponentialBackoffRetry exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 2147483647);
                this.curatorFramework = CuratorFrameworkFactory.newClient(this.zookeeperConnectionStr, (RetryPolicy)exponentialBackoffRetry);
                if (this.nameSpace != null && "".equals(this.nameSpace)) {
                    this.curatorFramework.usingNamespace(this.nameSpace);
                }
                this.curatorFramework.start();
                TreeCache treeCache = new TreeCache(this.curatorFramework, this.ruleBasePath);
                treeCache.getListenable().addListener(this);
                treeCache.start();
            } else {
                throw new RuntimeException("ruleBasePath cannot be null");
            }
        } else {
            throw new RuntimeException("zookeeperConnectionStr cannot be null");
        }
    }

    synchronized void loadHolidays() {
        if (this.holidaysUrl != null && !this.holidaysUrl.equals("")) {
            String result = HttpUtil.post(this.holidaysUrl, new HashMap<String,Object>());
            JSONObject jo = JSONObject.parseObject(result);
            Holidays.holidays = JSON.parseArray(jo.get("data").toString(), HolidaysModel.class);
        }
    }


    synchronized DroolsRulePackage loadRule(String groupId, String artifactId, String version) {
        log.info("通过eds获取规则配置...................");
        Rule rule = RuleBuilder.newBuilder()
                .groupId(groupId)
                .artifactId(artifactId)
                .version(version)
                .build();
        DroolsRulePackage droolsRulePackage = (DroolsRulePackage) invoke(this.ruleProviderServiceCode,rule, DroolsRulePackage.class);

        droolsRulePackage.compile(this.ruleCompiler);
        return droolsRulePackage;
    }

    private Object invoke(String ruleProviderServiceCode, Rule rule, Class<DroolsRulePackage> droolsRulePackageClass) {
        return null;
    }

    public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
        String data;
        String[] datas;
        String removeData;
        String[] removeDatas;
        String updateData;
        String[] updateDatas;
        switch (event.getType()) {
            case NODE_ADDED:
                data = new String(event.getData().getData());
                datas = data.split(":");
                if (datas.length == 2) {
                    if (datas[0].equals("holidays")) {
                        loadHolidays(); break;
                    }
                    refreshVersionReference(datas[0], datas[1]);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("NODE_ADDED: PATH:" + event.getData().getPath() + ",DATA:" + new String(event.getData().getData()));
                    }
                }
                break;


            case NODE_REMOVED:
                removeData = new String(event.getData().getData());
                removeDatas = removeData.split(":");
                if (removeDatas.length >= 1) {
                    removeVersionReference(removeDatas[0]);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("NODE_UPDATED: PATH:" + event.getData().getPath() + ",DATA:" + new String(event.getData().getData()));
                    }
                }
                break;

            case NODE_UPDATED:
                updateData = new String(event.getData().getData());
                updateDatas = updateData.split(":");
                if (updateDatas.length == 2) {
                    if (updateDatas[0].equals("holidays")) {
                        loadHolidays(); break;
                    }
                    refreshVersionReference(updateDatas[0], updateDatas[1]);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("NODE_REMOVED:PATH:" + event.getData().getPath() + ",DATA:" + new String(event.getData().getData()));
                    }
                }
                break;
        }
    }




    public void setZookeeperConnectionStr(String zookeeperConnectionStr) {
        this.zookeeperConnectionStr = zookeeperConnectionStr;
    }

    public void setRuleBasePath(String ruleBasePath) {
        this.ruleBasePath = ruleBasePath;
    }

    public void setRuleProviderServiceCode(String ruleProviderServiceCode) {
        this.ruleProviderServiceCode = ruleProviderServiceCode;
    }


    public void setEsbClient(ESBClient esbClient) {
        this.esbClient = esbClient;
    }

    public void setRuleCompiler(DroolsRuleCompiler ruleCompiler) {
        this.ruleCompiler = ruleCompiler;
    }

    public DroolsRuleCompiler getRuleCompiler() {
        return this.ruleCompiler;
    }

    public void setHolidaysUrl(String holidaysUrl) {
        this.holidaysUrl = holidaysUrl;
    }

    public void setNameSpace(String nameSpace) {
        this.nameSpace = nameSpace;
    }
}